﻿using AuthExtensions.Auth;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace AuthExtensions
{
    public static class AuthExtensions
    {
        public static void AddAuth(this IServiceCollection services, IConfigurationSection section)
        {
            var config = section.Get<AuthConfig>() ?? new AuthConfig();
            services.Configure<AuthConfig>(section);
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton<IAuthUser, AuthUser>();
            services.AddSingleton<IAuthToken, AuthToken>();
            
            services.AddAuthentication().AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = true;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(config.SigningKey)),
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidIssuer = config.ValidIssuer,
                    ValidAudience = config.ValidAudience,
                };
                if (config.QueryToken)
                {
                    x.Events = new JwtBearerEvents
                    {
                        /*OnTokenValidated = context =>   
                        {
                            var chche= context.HttpContext.RequestServices.GetService<ICache>();

                            var tenantCode = context.HttpContext.GetRouteValue("__tenant__")?.ToString() ?? "";

                            if (!string.IsNullOrEmpty(tenantCode) && TenantJwtKeys.TryGetValue(tenantCode, out var signingKey))
                            {
                                var tokenValidationParameters = (context.Options as JwtBearerOptions).TokenValidationParameters.Clone();
                                tokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(signingKey));
                                var tokenHandler = new JwtSecurityTokenHandler();
                                var principal = tokenHandler.ValidateToken(context.SecurityToken as JwtSecurityToken, tokenValidationParameters, out var validatedToken);
                                context.Principal = principal;
                            }
                            else
                            {
                                context.Fail("Invalid Tenant");
                            }
                            return Task.CompletedTask;
                        },*/
                        OnMessageReceived = context =>
                        {
                            var accessToken = context.Request.Query["access_token"];

                            // If the request is for our hub... {/Tenant1/MessageHub}
                            var path = context.HttpContext.Request.Path;
                            if (path != null && path.Value != null && !string.IsNullOrEmpty(accessToken) &&
                                (config.QueryPaths != null && config.QueryPaths.Length > 0
                                && config.QueryPaths.Any(x => path.Value.ToLower().Contains(x.ToLower()))))
                            {
                                // Read the token out of the query string
                                context.Token = accessToken;
                            }
                            return Task.CompletedTask;
                        }
                    };
                }

            });
            services.AddAuthorization();
        }

        public static void UseAuth(this WebApplication app)
        {
            app.UseAuthentication();
            app.UseAuthorization();
        }
    }
}
